//
//  main.m
//  07-内存管理
//
//  Created by 曹曹 on 16/7/12.
//  Copyright © 2016年 曹曹. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "SuperMan.h"

int main(int argc, const char * argv[]) {
#pragma mark - 内存问题:
    // 一.内存溢出
    //    内存过多导致溢出, 产生Crash
    // 二.野指针
    //    指针指向未知区域, 指向一块被释放的内存
    //    0f0x0afdsja
    /** 
     * 内存管理方式
     */
    // 1.垃圾回收机制: 只有Mac上有
    // iOS内存管理机制: 引用计数
    // iOS内存管理方式:
    // 2.MRC: 手动管理引用计数
    // 3.ARC: 自动管理引用计数(现在常用)
    // 注意: ARC基于MRC进行管理, 系统帮程序员添加了内存管理的代码
    // retain, alloc, copy需要进行内存管理(类方法或者构造器中包含autorelease所以不需要进行内存管理)
#pragma mark - 内存管理: 引用计数(计数器)
    // 有retain, alloc, copy会对引用计数 +1
    // 有release, autorelease会对引用计数 -1
    // 当对象的计数器为0时, 系统会调用对应的dealloc释放空间
    // 注意: 内存管理, 在完成对象操作后, 再进行释放
    SuperMan *man = [[SuperMan alloc] init];
    NSLog(@"%ld", man.retainCount);/**< 1 */
    [man retain];
    [man release];
    NSLog(@"%@, %ld", man, man.retainCount);/**< 1 */
    // 集合类型, 会对对象进行引用计数
    // addObject 对对象进行引用计数 +1
    // removeObject 对对象进行引用计数 -1
    NSMutableArray *array = [NSMutableArray arrayWithObject:man];
    NSLog(@"向数组中添加后的引用计数:%ld", man.retainCount);/**< 2 */
    [array removeAllObjects];
    NSLog(@"从数组中移除后的引用计数:%ld", man.retainCount);/**< 1 */
#pragma mark - ARC
    // strong(ARC下使用, 强引用, 引用计数 +1), weak(用于对象类型(NSObject子类), 弱引用, 对象被释放时会自动置空(将代理置空), 但不会对对象做retain操作)
    // retain(MRC下使用, 强引用, 引用计数 +1),
    // copy(拷贝, 把对象拷贝一份, 原来的引用计数不变, 新的 +1)
    // assgin(仅应用于简单数据类型, 不会产生引用计数)
#pragma mark - 协议
    // 协议三步
    // 1.声明协议, 声明对应的方法
    // 2.签订协议
    // 3.实现协议方法
#pragma mark - 实现对象的拷贝
    // 1.签订NSCopying协议
    // 2.实现协议方法CopyWithZone
    SuperMan *newMan = [man copy];
    NSLog(@"newMan:%@ - oldMan:%@", newMan, man);/**< 生成新的空间 */
    newMan.name = @"鱼摆摆";
    newMan.sexual = @"女";
#pragma mark - KVC(NSObject)
    // 只要是NSObject的子类就包含这些方法
    // Key-Value-Coding 键值编码, ******间接访问成员(实例)变量******的方式
    /** valueForKey */
    id name = [newMan valueForKey:@"name"];
    NSLog(@"name:%@", name);
    /** setValue: forKey: */
    [newMan setValue:@"章鱼宝宝" forKey:@"name"];
    NSLog(@"newName:%@", newMan.name);
    SuperMan *gayMan = [[SuperMan alloc] init];
    gayMan.gayBoy = newMan;
    /** valueForKeyPath */
    id boyName = [gayMan valueForKeyPath:@"gayBoy.name"];
    NSLog(@"boyName:%@", boyName);
    [gayMan release];
    /** setValue: forKeyPath: */
    [gayMan setValue:@"李四" forKeyPath:@"gayBoy.name"];
    NSLog(@"%@", gayMan.gayBoy.name);
    NSDictionary *dic = [[NSDictionary alloc] initWithObjectsAndKeys:@"123345", @"id", @"哈哈哈啊哈哈哈", @"description", nil];
    SuperMan *dicMan = [[SuperMan alloc] init];
    [dicMan setValuesForKeysWithDictionary:dic];
#pragma mark - MRC和ARC混编
    // 加在Build Phases中的编译source下
    // 如果在ARC工程中使用MRC文件
    // -fno-objc-arc
    // 在MRC工程中使用ARC文件
    // -fobjc-arc
    return 0;
}
